﻿using nhCore.nMessage;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;

namespace nhCore
{
    /// <summary>
    /// TcpServer接口
    /// </summary>
    public class TcpServerIO : IO
    {
        /// <summary>
        /// 回调函数，侦听来自 TCP 网络客户端的连接
        /// </summary>
        private TcpListener TcpListener { get; }

        /// <summary>
        /// 为释放资源，保留TcpClient
        /// </summary>
        private HashSet<TcpClient> TcpClientList { get; set; } = new HashSet<TcpClient>();

        /// <summary>
        /// 监听IP地址
        /// </summary>
        private IPAddress IPAddress { get; set; }

        /// <summary>
        /// 监听端口
        /// </summary>
        private int Port { get; set; }

        /// <summary>
        /// 构造函数，异步TCP服务器，装载参数中传递来的端口号
        /// </summary>
        /// <param name="port"></param>
        public TcpServerIO(int port)
        {
            this.Port = port;
            IPAddress = IPAddress.Any;
            TcpListener = new TcpListener(IPAddress, this.Port);
            Name = "TCP服务器";
            TimeOut = 200;
        }

        /// <summary>
        /// 加入在线客户端列表
        /// </summary>
        /// <param name="client"></param>
        private void AddClient(TcpClient client)
        {
            lock (TcpClientList)
            {
                TcpClientList.Add(client);
            }
        }

        /// <summary>
        /// 从在线客户端列表中移出
        /// </summary>
        /// <param name="client"></param>
        private void RemoveClient(TcpClient client)
        {
            lock (TcpClientList)
            {
                TcpClientList.Remove(client);
            }
        }

        /// <summary>
        /// 有客户端连接上来
        /// </summary>
        /// <param name="iar"></param>
        private void AcceptCallback(IAsyncResult iar)
        {
            if (iar.AsyncState is not TcpListener tlLs) { return; }//异步接受传入的连接尝试，并创建新的 TcpClient 来处理远程主机通信。
            if (IsOpened)
            {
                TcpClient client = tlLs.EndAcceptTcpClient(iar); //异步接受传入的连接尝试，并创建新的 TcpClient 来处理远程主机通信。
                client.ReceiveBufferSize = 256;
                client.SendBufferSize = 256;
                client.ReceiveTimeout = 100;
                client.SendTimeout = 100;

                AddClient(client);
                IOListener.Connected(this, client);//NHServer实现

                try
                {
                    tlLs.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), tlLs); //下一个连接尝试
                }
                catch (Exception) { }
            }
        }

        /// <summary>
        /// 数据读取完成后的回调函数
        /// </summary>
        /// <param name="iar">异步操作的状态，委托时用户自定义参数，用以区分客户端及缓冲</param>
        private void ReadCallback(IAsyncResult iar)
        {
            if (iar.AsyncState is not ReadAsyncResult rarResut) { return; }
            TcpClient client = rarResut.Client;
            if (client.Client.Connected)
            {
                int len;
                try
                {
                    NetworkStream nStream = client.GetStream();
                    len = nStream.EndRead(iar);
                }
                catch (Exception) { len = 0; }

                if (len < 1)
                {
                    RemoveClient(client);
                    client.Close();
                    IOListener.DisConnected(this, client);
                    IOListener.Error($"TcpServerIO.ReadCallback() len={len}");
                }
                else
                {
                    byte[] buffer = new byte[len];
                    Array.Copy(rarResut.Buffer, buffer, len);//返回数据复制到与返回长度一致的数组
                    //todo: 回调后再调用
                    //IConn.Received(this, client, buffer);或IOListener.Received(this, client, buffer);
                    if (client.Connected)
                    {
                        try
                        {   //为下一次委托
                            client.GetStream().BeginRead(rarResut.Buffer, 0, rarResut.Buffer.Length, new AsyncCallback(ReadCallback), rarResut);
                        }
                        catch (Exception ex)
                        {
                            RemoveClient(client);
                            client.Close();
                            IOListener.DisConnected(this, client);
                            IOListener.Error($"TcpServerIO.ReadCallback(), {ex.Message}");
                        }
                    }
                    else
                    {
                        RemoveClient(client);
                        IOListener.DisConnected(this, client);
                        IOListener.Error($"TcpServerIO.ReadCallback() client.Connected={client.Connected} ");
                    }
                }
            }
        }

        /// <summary>
        /// 开始侦听
        /// </summary>
        /// <returns></returns>
        public override bool Open(bool asyncComm = false)
        {
            if (IsOpened)
            {
                NMessage.Warn($"TCP监听服务已经在运行，监听地址：127.0.0.1:{Port}");
            }
            else
            {
                TcpListener.Start();
                IsOpened = true;
                //开始侦听，启动异步调用
                TcpListener.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), TcpListener);
                NMessage.Message($"TCP监听服务开始运行，监听地址：127.0.0.1:{Port}");
            }
            return true;
        }

        /// <summary>
        /// 服务端端口关闭
        /// </summary>
        /// <returns></returns>
        public override bool Close()
        {
            if (IsOpened)
            {
                IsOpened = false;
                try
                {
                    TcpListener.Stop();
                }
                catch (Exception)
                {

                }
                lock (TcpClientList)
                {
                    foreach (var client in TcpClientList)
                    {
                        client.Close();
                        IOListener.DisConnected(this, client);
                    }
                    TcpClientList.Clear();
                }
            }
            return true;
        }

        public override object SendAccept(object client, object bytes)
        {
            byte[] writeData = (bytes as byte[])!;
            TcpClient c = (client as TcpClient)!;
            byte[] readData = [];
            try
            {
                c.GetStream().Write(writeData, 0, writeData.Length);
                Thread.Sleep(TimeOut);
                byte[] tmp = new byte[256];

                int len = c.GetStream().Read(tmp, 0, tmp.Length);
                if (len > 0)
                {
                    readData = new byte[len];
                    Array.Copy(tmp, readData, len);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("TcpSecerIO.SendAccept()中异常");
                if (!c.Connected)
                {
                    c.Close();
                    IOListener.DisConnected(this, c);
                    RemoveClient(c);
                    IOListener.Error($"TcpServerIO.Send(), {ex.Message}");
                }
            }
            return readData;
        }

        public override bool Send(object client, in object bytes)
        {
            byte[] writeData = (bytes as byte[])!;
            bool result = false;
            TcpClient c = (client as TcpClient)!;
            try
            {
                c.GetStream().Write(writeData, 0, writeData.Length);
                result = true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("TcpSecerIO.SendAccept()中异常");
                if (!c.Connected)
                {
                    c.Close();
                    IOListener.DisConnected(this, c);
                    RemoveClient(c);
                    IOListener.Error($"TcpServerIO.Send(), {ex.Message}");
                }
            }
            return result;
        }
    }
}